#include <cstdio>
#include <SDL2/SDL.h>
#include "minIni.h"
#include "config.h"
#include "spriteanimator.h"
#include "sprite.h"

using namespace Oribi;

Oribi::SpriteAnimFrame getFrame(std::string name, int frame, int defW, int defH, Uint32 defTicks, Oribi::ConfigFile& f)
{
    SDL_Rect rect;
    Uint32 ticks;
    char buf[16];

    sprintf(buf, "f%dx", frame);
    rect.x = f.geti(name, buf);

    sprintf(buf, "f%dy", frame);
    rect.y = f.geti(name, buf);

    sprintf(buf, "f%dw", frame);
    rect.w = f.geti(name, buf);

    sprintf(buf, "f%dh", frame);
    rect.h = f.geti(name, buf);

    if (!rect.w && !rect.h)
    {
        rect.w = defW;
        rect.h = defH;
    }

    sprintf(buf, "f%dticks", frame);
    ticks = f.geti(name, buf);

    if (!ticks)
    {
        sprintf(buf, "f%dfps", frame);
        ticks = f.geti(name, buf);

        if (!ticks)
            ticks = defTicks;
        else
            ticks = 1000 / ticks;
    }

    printf("Frame, rect = %d %d %d %d, ticks = %d\n",
           rect.x, rect.y, rect.w, rect.h, ticks);
    return {rect, ticks};
}

SpriteAnimation::SpriteAnimation(std::string name, ConfigFile& f)
{
    loadFromFile(name, f);
}

bool SpriteAnimation::loadFromFile(std::string name, ConfigFile& f)
{
    int nFrames = f.geti(name, "frames");

    printf("Load animation %s\n", name.c_str());
    printf("nFrames = %d\n", nFrames);

    if (!nFrames)
    {
        return false;
    }

    int defW, defH;
    Uint32 defTicks;

    printf("Load animation %s\n", name.c_str());

    defW = f.geti(name, "width");
    defH = f.geti(name, "height");
    defTicks = f.geti(name, "ticksPerFrame");

    printf("w = %d, h = %d, ticks = %d\n",
           defW, defH, defTicks);

    if (!defTicks)
    {
        defTicks = 1000 / f.geti(name, "framesPerSecond", 20);
    }

    for (int i = 0; i < nFrames; ++i)
    {
        printf("Load frame from file\n");
        frames.push_back(getFrame(name, i, defW, defH, defTicks, f));
        printf("Loaded that bitch\n");
    }

    return true;
}

SprAnimRun::SprAnimRun(const SpriteAnimation& an, int loops, bool destruct):
    anim(an),
    destroy(destruct),
    nLoopsRemaining(loops)
{
    state = SprAnimRunning;
    resetTime();
    frame = 0;
    nFrames = anim.frames.size();
    printf("New SprAnimRun with %d frames\n", nFrames);
}

SprAnimRun::SprAnimRun(const SprAnimRun& rhs):
    anim(rhs.anim),
    state(rhs.state),
    destroy(rhs.destroy),
    frame(rhs.frame),
    nFrames(rhs.nFrames),
    nLoopsRemaining(rhs.nLoopsRemaining),
    startTime(rhs.startTime),
    switchTime(rhs.switchTime){}


SpriteAnimator *SprAnimRun::clone() const
{
    return new SprAnimRun(*this);
}

int SprAnimRun::switchFrame(Sprite& spr)
{
    if (frame >= nFrames - 1)
    {
        frame = 0;
        if (nLoopsRemaining > -1)
        {
            nLoopsRemaining--;
            if (nLoopsRemaining < 1)
            {
                if (destroy)
                    return SPR_ANIM_DESTROY;
                else
                    return SPR_ANIM_REMOVE;
            }
        }
    }
    else
    {
        frame++;
    }

    spr.rect = anim.frames[frame].rect;
    return SPR_ANIM_DO_NOTHING;
}

int SprAnimRun::animateSprite(Sprite& spr)
{
    Uint32 time = SDL_GetTicks();
    int stat = SPR_ANIM_DO_NOTHING;

    if (!anim.frames.size())
        return SPR_ANIM_DESTROY;

    printf("Run SprAnimRun, frame %d\n", frame);
    if (time - switchTime >= anim.frames[frame].ticks)
    {
        switchTime = time;
        stat = switchFrame(spr);
    }
    return stat;
}

void SprAnimRun::setDestroy(bool d)
{
    destroy = d;
}

bool SprAnimRun::getDestroy()
{
    return destroy;
}

void SprAnimRun::resetTime()
{
    startTime = SDL_GetTicks();
    switchTime = startTime;
}

void SprAnimRun::pause()
{
    state = SprAnimPaused;
}

void SprAnimRun::run()
{
    state = SprAnimRunning;
    resetTime();
}

void SprAnimRun::stop()
{
    frame = 0;
    state = SprAnimPaused;
}

void SprAnimRun::restart()
{
    frame = 0;
    state = SprAnimPaused;
}

void SprAnimRun::restart(int nLoops)
{
    frame = 0;
    state = SprAnimPaused;
    nLoopsRemaining = nLoops;
}
